package com.gtlab1207.br_security.ctrls;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gtlab1207.br_security.common.Result;
import com.gtlab1207.br_security.models.domain.Encryption;
import com.gtlab1207.br_security.services.EncryptionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.util.*;

/**
 * 消息加密
 */
@Slf4j
@RestController
@RequestMapping("/message/")
public class MessageEncryptionCtrl extends BaseCtrl{
    @Value("${customize.server1.ip}")
    private String ip;
    @Value("${customize.server1.port}")
    private String port;
    @Value("${customize.server2.ip}")
    private String ip2;
    @Value("${customize.server2.port}")
    private String port2;
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    EncryptionService encryptionService;


//    @GetMapping("/test")
//    public Result test(){
//        return this.send(200,"test");
//    }
    @PostMapping("/save_key")
    /*
    restTemplate使用post请求，那么方法参数必须加@RequestBody注解，否则接收不到restTemplate传过来的请求体参数。
     @RequestBody注解只接收json字符串格式数据，并且修改contentType的值为:application/json;
     */
    public Result saveKey(@RequestBody Encryption record) {
//        System.out.println(record.toString());
        if(StpUtil.isLogin()){
            try {
                encryptionService.addEncryption(record);
            }catch (RuntimeException e){
                log.error("saveKey():保存{}失败",record.toString());
                return this.send(500,e.getMessage());
            }
            return this.send(200,"保存成功");
        }else {
            return this.send(200,"未登录");
        }


    }
    @PostMapping("/delete_key")
    public Result deleteKey(@RequestBody Encryption record){
//        System.out.println(record.toString());
        if(StpUtil.isLogin()){
            encryptionService.deleteEncryption(record.getProvideOrg(),record.getTopicId());
            return this.send(200,"删除成功");
        }else {
            return this.send(200,"未登录");
        }

    }

    @PostMapping(value = {"/encryption/{provideOrg}/{topicId}"})
    public Result messageEncryption(@PathVariable(value = "provideOrg", required = false) String provideOrg,
                                    @PathVariable(value = "topicId", required = false) String topicId,
                                    @RequestBody String jsonString) {

//        System.out.println("AES加密前：" + jsonString);
        //进入消息队列
        //发送给用户
        if(StpUtil.isLogin()){
            JSONObject jsonObject = JSONObject.parseObject(jsonString);
            return getResult(provideOrg, topicId, jsonObject);
        }else {
            return this.send(200,"未登录");
        }
    }

    @PostMapping(value = {"/encryption_xml/{provideOrg}/{topicId}"}, consumes = {MediaType.APPLICATION_XML_VALUE})
    public Result messageEncryptionForXML(@PathVariable(value = "provideOrg", required = false) String provideOrg,
                                          @PathVariable(value = "topicId", required = false) String topicId,
                                          @RequestBody String xmlObject) {
//        System.out.println("AES(xml)加密前：" + xmlObject);
        if(StpUtil.isLogin()){
            return getResult(provideOrg, topicId, xmlObject);
        }else {
            return this.send(200,"未登录");
        }

    }

    private Result getResult(String provideOrg, String topicId, Object  data) {
        topicId = topicId == null ? "" : topicId;
        //根据提供机构和订阅号，拿到密钥,没有就生成新的密钥
        String key = null;
        Encryption encryObject = encryptionService.selectEncryptionById(provideOrg, topicId);
        if (encryObject != null) {
            key = encryObject.getPrivateKey();
        } else {
            key = produceKey(topicId);
            //保存订阅号、密钥到数据库
            Encryption record = new Encryption();
            record.setProvideOrg(provideOrg);
            record.setTopicId(topicId);
            record.setPrivateKey(key);
            record.setCreateBy("ty");
            record.setUpdateBy("ty");
            System.out.println(record.toString());
            //向另外的服务器保存一份数据
            Result result=null;
            try{
                result=restTemplate.postForObject("http://" + ip + ":" + port + "/message/save_key", record, Result.class);

            }catch (RestClientException e){
                log.error("restTemplate出现异常，异常信息为：{}",e.getMessage());
            }
            Integer resultCode =(Integer)result.getStatus().get("code");
            if(resultCode!=200){
                log.error("restTemplate请求http://{}:{}/message/save_key状态码为{}，异常信息为：{}",ip,port,500,"没有保存成功");
                return this.send(500,"没有保存成功");
            }
            try{
                result=restTemplate.postForObject("http://" + ip2 + ":" + port2 + "/message/save_key", record, Result.class);

            }catch (RestClientException e){
                log.error("restTemplate出现异常，异常信息为：{}",e.getMessage());
            }
            resultCode =(Integer)result.getStatus().get("code");
            if(resultCode!=200){
                log.error("restTemplate请求http://{}:{}/message/save_key状态码为{}，异常信息为：{}",ip,port,500,"没有保存成功");
                return this.send(500,"没有保存成功");
            }
            encryptionService.addEncryption(record);
        }
        // 加密 session
        String encryptedText =null;
        if(data instanceof String){
            encryptedText = SaSecureUtil.aesEncrypt(key, (String)data);
        }else if (data instanceof JSONObject){
            encryptedText = SaSecureUtil.aesEncrypt(key, toJSONString(data));
        }
//        System.out.println("AES加密后：" + encryptedText);
        //封装密文
        Map<String, String> result = new HashMap<String, String>();
        result.put("key", key);
        result.put("encryptedText", encryptedText);
        return this.send(result);
    }

    /**
     * @param topicId 订阅号
     * @param provideOrg     提供机构    （广州区管、三亚区管、广州白云机场、南方航空公司、科伦坡区管、肯尼亚区管）
     * @param encryptedText  密文
     * @return 明文
     */
    @PostMapping("/decryption")
    public Result messageDecryption(String topicId, String provideOrg, String encryptedText) {
//        System.out.println("subscriptionId:"+subscriptionId+"provideOrg:"+provideOrg+"encryptedText:"+encryptedText);
        if(StpUtil.isLogin()){
            //根据提供机构和订阅号，拿到密钥（是我自己设计的表，在我们的数据库中）
            Encryption record = encryptionService.selectEncryptionById(provideOrg, topicId);
            if (record == null) {
                log.error("messageDecryption()出现异常，状态码为{}，异常信息为：{}",500,"没有保存成功");

                return this.send(500, "没有查到唯一密钥");
            }
            String key = record.getPrivateKey();

            // 解密
            String result = SaSecureUtil.aesDecrypt(key, encryptedText);
//        System.out.println("AES解密后：" + result);

            return this.send(result);
        }else {
            return this.send(200,"未登录");
        }

    }

    private String produceKey(String subscriptionId) {
        //获取时间戳：System.currentTimeMillis()/new Date().getTime()/Calendar.getInstance().getTimeInMillis()
        return subscriptionId + UUID.randomUUID().toString() + System.currentTimeMillis();
    }

    public String toJSONString(Object jsonObject) {

        return JSON.toJSONString(jsonObject);
    }

    public Object toJSONObject(String jsonString) {

        JSONObject jsonObject = JSONObject.parseObject(jsonString);

        //这样就可以将一串参数转化成json对象了，然后通过下面指定的key获取特定的值，如下面所示
        //String imei= (String) jsonObject.get("imei");
        return jsonObject;
    }


}
